/*
 * Università degli Studi di Trento
 * Facoltà di Scienze MM.FF.NN.
 * Corso di Laurea Triennale in Informatica
 * A.A. 2011/2012
 * Progetto per il corso di Sistemi Operativi 1
 * Progetto 3: 
 * Autori:
 * Bertoldi Lorenzo 155863
 * Cattin Cosso Manuel 146607
 * Parrello Nicola 145610
 */

/********************************************************************************
  Questa file contiene l implementazinoe dei metodi collegati a threadFigli.
********************************************************************************/


#include <signal.h>

#include "threadFiglio.h"
#include "definizioni.h"


/*
 * costruttore :
 * Alloca lo spazio per la struttura ThreadFiglio e istanzia le variabili
 * Di default il figlio e' addormentato
 * Restituisce il puntatore.
*/
pThreadFiglio ThreadFiglio_create (char * comando){
    pThreadFiglio  thread= new(ThreadFiglio);
    thread->command=comando;
    thread->state=SLEEP;
    thread->fileAperto=false;
    if(pipe(thread->pipe)==-1){
        perror("pipe");
        thread->pipeApertaRead=false;
        thread->pipeApertaWrite=false;
        exit(1);
    }else{
        thread->pipeApertaRead=true;
        thread->pipeApertaWrite=true;
    }
    return thread;
}

/*
 * setPid :
 * imposta il pid del figlio
*/
void ThreadFiglio_setPid (pThreadFiglio th, int pid){
    th->pid=pid;
}

/*
 * start :
 * se il figlio dormiva viene avviato
 * Ritorna lo stato del figlio
*/
State ThreadFiglio_start(pThreadFiglio th){
    if(th->state==SLEEP){
        if(kill(th->pid,SIGCONT)==-1){
            perror("Impossibile inviare il segnale di start");
        }else{
            th->state=RUN;
        } 
    }
    return th->state;   
}

/*
 * closePipeRead :
 * Chiude la pipe in scrittura
 * Restituisce -1 in caso di insuccesso e 0 altrimenti
*/
int ThreadFiglio_closePipeRead (pThreadFiglio th){
    if(close(th->pipe[0])==-1){
        printf("Errore durante la chiusura della pipe in lettura del thread: %s %i\n",th->command,th->pid);
        return -1;
    }else{
        th->pipeApertaRead=false;
        return 0;
    }
}

/*
 * closePipeWrite :
 * Chiude la pipe in scrittura
 * Restituisce -1 in caso di insuccesso e 0 altrimenti
*/
int ThreadFiglio_closePipeWrite (pThreadFiglio th){
    if(close(th->pipe[1])==-1){
        printf("Errore durante la chiusura della pipe in scrittura del thread: %s %i\n",th->command,th->pid);
        return -1;
    }else{
        th->pipeApertaWrite=false;
        return 0;
    }
}

/*
 * terminate :
 * il figlio viene terminato
 * Ritorna lo stato del figlio
*/
State ThreadFiglio_terminate(pThreadFiglio th){
    if(kill(th->pid,SIGINT)!=-1){
        printf("Errore durante l'invio del segnale al thread: %s %i\n",th->command,th->pid);
    }else{
        th->pid=FINISH;
    }
    return th->state;   
}

/*
 * finish :
 * mette lo stato finish al thread e chiude la pipe in scrittura
 * Ritorna lo stato del figlio
*/
State ThreadFiglio_setFinish(pThreadFiglio th){
    th->state=FINISH;
    if(close(th->pipe[1])==-1){
        perror("Errore durante la chiusura della pipe in scrittura");
    }else{
        th->pipeApertaWrite=false;
    }
    return th->state;
}

/*
 * getState : 
 * return: lo stato attuale del thread
*/
State ThreadFiglio_getState(pThreadFiglio th){
    return th->state;
}

/*
 * distruttore:
 * Invia il segnale di terminazione al thread, rilascia le risorse occupate
 * return: un intero, se 0  distruzione avvenuta
                      se >0 distruzione non avvenuta
*/
int ThreadFiglio_destroy(pThreadFiglio th){
    if(th->state!=FINISH){
        ThreadFiglio_terminate(th);
    }
    if(th->pipeApertaRead==true){    
        if(close(th->pipe[0])==-1){
            perror("Errore durante la chiusura della pipe in lettura");
        }
    }
    
    if(th->pipeApertaWrite==true){    
        if(close(th->pipe[1])==-1){
            perror("Errore durante la chiusura della pipe in scrittura");
        }
    }
    if(th->fileAperto==true){
        if(close(th->file)==-1){
            perror("Errore durante la chiusure del file del processo figlio");
        }
    }
    th->command=NULL;
    delete(th);
    return 0;
}